﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PercolationTree.Model
{
    class Tree
    {
        #region Private Members
        private IList<Layer> m_Layers = new List<Layer>();
        private Random random = new Random();
        #endregion

        #region Public
        public Tree()
        {
            Node rootNode = new Node();
            Layer rootLayer = new Layer();
            rootLayer.AddNode(rootNode);
            m_Layers.Add(rootLayer);
        }
        public void AddChildNode(Node owner, Node child)
        {
            owner.Subnodes.Add(child);
            child.Supernode = owner;

            Layer ownerLayer = m_Layers.Where(layer => layer.Nodes.Contains(owner)).First();
            int index = m_Layers.IndexOf(ownerLayer);
            if (index == m_Layers.Count - 1)
                m_Layers.Add(new Layer());
            Layer childLayer = m_Layers[index + 1];
            childLayer.AddNode(child);
        }
        public IList<Layer> Layers
        {
            get
            {
                return m_Layers;
            }
        }
        public void Percolate(float invalidationChance)
        {
            if (invalidationChance < 0.0f && 1.0f < invalidationChance) throw new ArgumentException("The invalidationChance must be clamped by (0.0f, 1.0f)");

            Node rootNode = m_Layers.First().Nodes.First();
            ProcessPercolation(rootNode, invalidationChance);
        }
        #endregion

        #region Private Methods

        private void ProcessPercolation(Node node, float invalidationChance)
        {
            node.Type = NodeType.Valid;
            const int maxInt = 100;
            int randInt = random.Next(1, maxInt);
            if (maxInt * invalidationChance > randInt && node.Supernode != null)
                SpoilNodeAndChildren(node);
            else
                foreach (Node subnode in node.Subnodes)
                    ProcessPercolation(subnode, invalidationChance);
        }

        private void SpoilNodeAndChildren(Node node)
        {
            node.Type = NodeType.Invalid;
            foreach (Node subnode in node.Subnodes)
                SpoilNodeAndChildren(subnode);
        }

        #endregion
    }
}
